home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / linuxcon.000 / linuxcon / linuxconf-1.6 / netconf / daemons.c < prev    next >
C/C++ Source or Header  |  1996-08-01  |  14KB  |  565 lines

  1. #include <fcntl.h>
  2. #include <unistd.h>
  3. #include <limits.h>
  4. #include <signal.h>
  5. #include "netconf.h"
  6. #include "internal.h"
  7. #include "../paths.h"
  8. #include "../xconf/xconf.h"
  9. #include "netconf.m"
  10.  
  11. static NETCONF_HELP_FILE help_inetd("inetd");
  12. static CONFIG_FILE f_inetd (ETC_INETD_CONF,help_inetd,CONFIGF_PROBED);
  13. static NETCONF_HELP_FILE help_amd("amd");
  14. static CONFIG_FILE f_conf_amd (ETC_CONF_AMD_MAP,help_amd,CONFIGF_PROBED);
  15. static NETCONF_HELP_FILE help_gated("gated");
  16. static CONFIG_FILE f_gated (ETC_GATED_CONF,help_gated,CONFIGF_PROBED);
  17. static NETCONF_HELP_FILE help_ssh ("ssh");
  18. static CONFIG_FILE f_ssh_host_key (ETC_SSH_HOST_KEY,help_ssh,CONFIGF_PROBED);
  19.  
  20.  
  21. extern CONFIG_FILE f_exports;
  22.  
  23.  
  24. /* #Specification: daemon / classes
  25.     The class DAEMON is the base class. Each daemon (portmap, inetd, ...)
  26.     may have its own class where it generally overide the method
  27.     startif and stop.
  28. */
  29. #
  30. class DAEMON_INETD: public DAEMON{
  31.     /*~PROTOBEG~ DAEMON_INETD */
  32. public:
  33.     int restart (void);
  34.     int startif (void);
  35.     /*~PROTOEND~ DAEMON_INETD */
  36. };
  37. /*
  38.     Tell inetd to reread its configuration file
  39. */
  40. PUBLIC int DAEMON_INETD::restart()
  41. {
  42.     int ret = -1;
  43.     PROC *prc = process_find(path);
  44.     if (prc != NULL){
  45.         if (file_date (VAR_RUN_INETD_SIGHUP) < f_inetd.getdate()){
  46.             ret = signal (SIGHUP,"Signaling",VAR_RUN_INETD_SIGHUP);
  47.         }
  48.     }
  49.     return ret;
  50. }
  51. PUBLIC int DAEMON_INETD::startif()
  52. {
  53.     /* #Specification: inetd / strategy
  54.         inetd depend on /etc/inetd.conf. If the file is empty
  55.         or do not exist, then inetd is not need. It will be
  56.         killed, or not started.
  57.  
  58.         If inetd.conf is not empty, it will be started. If it is
  59.         already running and exports is younger than the process,
  60.         the signal SIGHUP is sent so inetd will reread inetd.conf.
  61.     */
  62.     return startif_file(ETC_INETD_CONF);
  63. }
  64. class DAEMON_PORTMAP: public DAEMON{
  65.     /*~PROTOBEG~ DAEMON_PORTMAP */
  66.     /*~PROTOEND~ DAEMON_PORTMAP */
  67. };
  68.  
  69. class DAEMON_AMD: public DAEMON{
  70.     /*~PROTOBEG~ DAEMON_AMD */
  71. public:
  72.     int restart (void);
  73.     int startif (void);
  74.     int stop (void);
  75.     /*~PROTOEND~ DAEMON_AMD */
  76. };
  77. /*
  78.     Stop the automounter
  79. */
  80. PUBLIC int DAEMON_AMD::stop ()
  81. {
  82.     return kill(SIGINT);
  83. }
  84. /*
  85.     Tell the automounter to reread its configuration file.
  86. */
  87. PUBLIC int DAEMON_AMD::restart ()
  88. {
  89.     /* #Specification: amd / restarting
  90.         When the map (/etc/conf.amd.map) is changed, amd is simply
  91.         restarted. It is killed with SIGINT and restarted. This is
  92.         weak as it is unmounting everything. On the other hand
  93.         I suspect that amd will be managed only in single user
  94.         mode so it does not matter. Some amd guru want to comment.
  95.     */
  96.     int ret = stop();
  97.     if (ret != -1) ret = start();
  98.     return ret;
  99. }
  100. /*
  101.     Restart amd if ETC_CONF_AMD_MAP is newer than the process
  102. */
  103. PUBLIC int DAEMON_AMD::startif ()
  104. {
  105.     /* #Specification: amd automounter / strategy
  106.         amd depends on /etc/conf.amd.map. If the file is empty
  107.         or do not exist, then amd is not need. It will be
  108.         killed, or not started.
  109.  
  110.         If /etc/conf.amd.map is not empty, it will be started. If it is
  111.         already running and exports is younger than the process,
  112.         it will be kill and restart
  113.     */
  114.     return startif_file (f_conf_amd);
  115. }
  116. class DAEMON_LPD: public DAEMON{
  117.     /*~PROTOBEG~ DAEMON_LPD */
  118.     /*~PROTOEND~ DAEMON_LPD */
  119. };
  120. class DAEMON_NFSD: public DAEMON{
  121.     /*~PROTOBEG~ DAEMON_NFSD */
  122. public:
  123.     int startif (void);
  124.     /*~PROTOEND~ DAEMON_NFSD */
  125. };
  126. /*
  127.     Restart nfsd if ETC_EXPORTS is newer than the process
  128. */
  129. PUBLIC int DAEMON_NFSD::startif ()
  130. {
  131.     /* #Specification: rpc.nfsd / strategy
  132.         rpc.nfsd depends on /etc/exports. If the file is empty
  133.         or do not exist, then rpc.nfsd is not need. It will be
  134.         killed, or not started.
  135.  
  136.         If exports is not empty, it will be started. If it is
  137.         already running and exports is younger than the process,
  138.         it will be kill and restart.
  139.  
  140.         I suspect there is a way to update nfsd without killing it.
  141.         Someone is aware of this ?
  142.     */
  143.     return startif_file(f_exports);
  144. }
  145. class DAEMON_MOUNTD: public DAEMON{
  146.     /*~PROTOBEG~ DAEMON_MOUNTD */
  147. public:
  148.     int startif (void);
  149.     /*~PROTOEND~ DAEMON_MOUNTD */
  150. };
  151.  
  152. /*
  153.     Restart mountd if ETC_EXPORTS is newer than the process
  154. */
  155. PUBLIC int DAEMON_MOUNTD::startif ()
  156. {
  157.     /* #Specification: rpc.mountd / strategy
  158.         rpc.mountd depends on /etc/exports. If the file is empty
  159.         or do not exist, then rpc.mountd is not need. It will be
  160.         killed, or not started.
  161.  
  162.         If exports is not empty, it will be started. If it is
  163.         already running and exports is younger than the process,
  164.         it will be kill and restart
  165.     */
  166.     return startif_file(f_exports);
  167. }
  168. class DAEMON_NAMED: public DAEMON{
  169.     /*~PROTOBEG~ DAEMON_NAMED */
  170. public:
  171.     int startif (void);
  172.     /*~PROTOEND~ DAEMON_NAMED */
  173. };
  174. /*
  175.     Restart named if ETC_NAMED_BOOT is newer than the process
  176. */
  177. PUBLIC int DAEMON_NAMED::startif ()
  178. {
  179.     /* #Specification: named / strategy
  180.         named depends on /etc/named.boot and many others configuration
  181.         files. If the file is empty or do not exist, then named
  182.         is not need. It will be killed, or not started.
  183.  
  184.         If named.boot is not empty, it will be started. If it is
  185.         already running and named.boot is younger than the process,
  186.         it will be killed and restarted.
  187.  
  188.         This is not completed yet. Normally, we should check for all
  189.         file processed by named to check if any one is younger. This
  190.         is not done now, as another project (the named editor) will
  191.         take care of named.
  192.     */
  193.     extern CONFIG_FILE f_boot;
  194.     return startif_file(f_boot);
  195. }
  196.  
  197. class DAEMON_GATED: public DAEMON{
  198.     /*~PROTOBEG~ DAEMON_GATED */
  199. public:
  200.     int restart (void);
  201.     int start (void);
  202.     int startif (void);
  203.     int stop (void);
  204.     /*~PROTOEND~ DAEMON_GATED */
  205. };
  206. /*
  207.     Restart gated if ETC_GATED_CONF is newer than the process
  208. */
  209. PUBLIC int DAEMON_GATED::startif ()
  210. {
  211.     /* #Specification: gated / strategy
  212.         gated depends on /etc/gated.conf.
  213.         If the file is empty or do not exist, then gated
  214.         is not need. It will be killed, or not started.
  215.  
  216.         If gated.conf is not empty, it will be started. If it is
  217.         already running and gated.conf is younger than the process,
  218.         it will be kill and restart.
  219.  
  220.     */
  221.     return startif_file(f_gated);
  222. }
  223.  
  224. /*
  225.     Tell gated to reread its configuration file
  226. */
  227. PUBLIC int DAEMON_GATED::restart()
  228. {
  229.     char buf[2000];
  230.     sprintf (buf,"%s restart",path);
  231.     return system (buf);
  232. }
  233. /*
  234.     Tell gated to stop
  235. */
  236. PUBLIC int DAEMON_GATED::stop()
  237. {
  238.     int ret = 0;
  239.     if (process_find(path)!=NULL){
  240.         char buf[2000];
  241.         sprintf (buf,"%s stop",path);
  242.         ret = system (buf);
  243.     }
  244.     return ret;
  245. }
  246. /*
  247.     Tell gated to start
  248. */
  249. PUBLIC int DAEMON_GATED::start()
  250. {
  251.     char buf[2000];
  252.     sprintf (buf,"%s start",path);
  253.     return system (buf);
  254. }
  255. class DAEMON_SENDMAIL: public DAEMON{
  256.     /*~PROTOBEG~ DAEMON_SENDMAIL */
  257. public:
  258.     int startif (void);
  259.     /*~PROTOEND~ DAEMON_SENDMAIL */
  260. };
  261. /*
  262.     Restart sendmail if ETC_SENDMAIL_CF is newer than the process
  263. */
  264. PUBLIC int DAEMON_SENDMAIL::startif ()
  265. {
  266.     /* #Specification: sendmail / strategy
  267.         sendmail depends on /etc/sendmail.cf.
  268.         If the file is empty or do not exist, then sendmail
  269.         is not need. It will be killed, or not started.
  270.  
  271.         If sendmail.cf is not empty, it will be started. If it is
  272.         already running and sendmail.cf is younger than the process,
  273.         it will be kill and restart.
  274.  
  275.     */
  276.     extern CONFIG_FILE f_sendmail;
  277.     return startif_file(f_sendmail);
  278. }
  279. class DAEMON_ROUTED: public DAEMON{
  280.     /*~PROTOBEG~ DAEMON_ROUTED */
  281. private:
  282.     void setcmdline (ROUTED&rt, char *cmdline);
  283. public:
  284.     int start (void);
  285.     int startif (void);
  286.     /*~PROTOEND~ DAEMON_ROUTED */
  287. };
  288.  
  289. PRIVATE void DAEMON_ROUTED::setcmdline(ROUTED &rt, char *cmdline)
  290. {
  291.     char buf[20];
  292.     rt.setoptions (buf);
  293.     sprintf (cmdline,"%s %s %s",path,args,buf);
  294. }
  295. extern NETCONF_HELP_FILE help_routed;
  296. static CONFIG_FILE f_run_routed (VAR_RUN_ROUTED_OPTIONS
  297.     ,help_routed,CONFIGF_MANAGED|CONFIGF_OPTIONNAL);
  298.  
  299. PUBLIC int DAEMON_ROUTED::start()
  300. {
  301.     ROUTED rt;
  302.     char cmdline[PATH_MAX];
  303.     setcmdline (rt,cmdline);
  304.     if (!simul_ison()){
  305.         FILE *fout = f_run_routed.fopen ("w");
  306.         if (fout != NULL){
  307.             fputs (cmdline,fout);
  308.             fclose (fout);
  309.         }
  310.     }
  311.     return system (cmdline);
  312. }
  313. PUBLIC int DAEMON_ROUTED::startif()
  314. {
  315.     int ret = 0;
  316.     ROUTED rt;
  317.     if (!rt.is_required()){
  318.         ret = stop();
  319.         if (!simul_ison()) unlink (f_run_routed.getpath());
  320.     }else{
  321.         PROC *prc = process_find(path);
  322.         if (prc == NULL){
  323.             ret = start();
  324.         }else{
  325.             /* #Specification: netconf / routed / /var/run/routed.options
  326.                 netconf save the command line option of routed in
  327.                 the file /var/run/routed.options each time it is
  328.                 started.
  329.  
  330.                 When checking the configuration, netconf read back
  331.                 the command line and compare with the configured
  332.                 one. If there is any difference, routed will
  333.                 be restarted.
  334.  
  335.                 I am not sure how appropriate it is to
  336.                 restarted. Maybe there is a clean way to kill routed
  337.                 so it will remove all routes and put it back when
  338.                 restart. Not sure here...
  339.             */
  340.             char old_cmdline[PATH_MAX];
  341.             old_cmdline[0] = '\0';
  342.             FILE *fin = f_run_routed.fopen ("r");
  343.             if (fin != NULL){
  344.                 fgets (old_cmdline,sizeof(old_cmdline)-1,fin);
  345.                 fclose (fin);
  346.             }
  347.             char cmdline[PATH_MAX];
  348.             setcmdline (rt,cmdline);
  349.             if (strcmp(cmdline,old_cmdline)!=0) ret = restart();
  350.         }
  351.     }
  352.     return ret;
  353. }
  354.     
  355.  
  356.  
  357. class DAEMON_YPBIND: public DAEMON{
  358.     /*~PROTOBEG~ DAEMON_YPBIND */
  359. private:
  360.     int set_domain (NIS_CONF&nis);
  361. public:
  362.     int start (void);
  363.     int startif (void);
  364.     /*~PROTOEND~ DAEMON_YPBIND */
  365. };
  366.  
  367. /*
  368.     Set the NIS domain name.
  369.     Return -1 if not defined, 0 if left unchanged or 1 if changed
  370. */
  371. PRIVATE int DAEMON_YPBIND::set_domain(NIS_CONF &nis)
  372. {
  373.     int ret = -1;
  374.     if (nis.configok()){
  375.         ret = 0;
  376.         const char *domain = nis.getdomain();
  377.         char buf[100];
  378.         if (getdomainname(buf,sizeof(buf)-1)==-1
  379.             || strcmp(buf,domain)!=0){
  380.             if (!simul_ison()){
  381.                 setdomainname(domain,strlen(domain)+1);
  382.             }
  383.             ret = 1;
  384.             net_prtlog (MSG_U(X_SETNISDOM,"Set NIS domain to %s\n"),domain);
  385.         }
  386.     }
  387.     return ret;
  388. }
  389. /*
  390.     Start ypbind.
  391. */
  392. PUBLIC int DAEMON_YPBIND::start ()
  393. {
  394.     int ret = 0;
  395.     NIS_CONF nis;
  396.     if (set_domain(nis) != -1){
  397.         const char *nisserver = nis.getserver();
  398.         if (nisserver != NULL){
  399.             char buf[2000];
  400.             sprintf (buf,"%s -ypset %s",path,args);
  401.             ret = -1;
  402.             if (system (buf) == 0){
  403.                 char ypset_path[PATH_MAX];
  404.                 strcpy (ypset_path,path);
  405.                 char *pt = ypset_path + strlen(ypset_path) -1;
  406.                 while (pt >= ypset_path && *pt != '/') pt--;
  407.                 if (pt >= ypset_path && *pt == '/'){
  408.                     *pt = '\0';
  409.                     sprintf(buf,"%s/ypset %s",ypset_path,nisserver);
  410.                 }else{
  411.                     sprintf(buf,"ypset %s",nisserver);
  412.                 }
  413.                 ret = system (buf);
  414.             }
  415.         }else{
  416.             ret = DAEMON::start();
  417.         }
  418.     }
  419.     return ret;
  420. }
  421. /*
  422.     Restart ypbind if ETC_DEFAULTDOMAIN is newer than the process
  423. */
  424. PUBLIC int DAEMON_YPBIND::startif ()
  425. {
  426.     /* #Specification: ypbind / strategy
  427.         ypbind is configured in the file /etc/conf.linuxconf
  428.         It provides the nis domain and optionnally the nis server
  429.         (If it can't be located by a broadcast).
  430.  
  431.         If the nis domain is defined, then ypbind is started.
  432.         Depending if a server is specified or not,
  433.         ypbind is started this way:
  434.  
  435.         #
  436.         No specified NIS server
  437.         
  438.         ypbind
  439.  
  440.         With a specified NIS server
  441.  
  442.         ypbind -ypset
  443.         ypset -h nisserver
  444.         #
  445.  
  446.         If the configuration file is newer than the current process,
  447.         it is killed and restarted.
  448.     */
  449.     int ret = 0;
  450.     NIS_CONF nis;
  451.     int status = set_domain(nis);
  452.     if (status == -1){
  453.         ret = stop();
  454.     }else if (status == 0){
  455.         if (process_find(path)==NULL) ret = start();
  456.     }else{
  457.         ret = restart();
  458.     }
  459.     return ret;
  460. }
  461. class DAEMON_KLOGD: public DAEMON{
  462.     /*~PROTOBEG~ DAEMON_KLOGD */
  463.     /*~PROTOEND~ DAEMON_KLOGD */
  464. };
  465. class DAEMON_SYSLOGD: public DAEMON{
  466.     /*~PROTOBEG~ DAEMON_SYSLOGD */
  467.     /*~PROTOEND~ DAEMON_SYSLOGD */
  468. };
  469. // Not really a daemon, but a system command
  470. class DAEMON_COMMAND: public DAEMON{
  471.     /*~PROTOBEG~ DAEMON_COMMAND */
  472.     /*~PROTOEND~ DAEMON_COMMAND */
  473. };
  474. class DAEMON_CROND: public DAEMON{
  475.     /*~PROTOBEG~ DAEMON_CROND */
  476.     /*~PROTOEND~ DAEMON_CROND */
  477. };
  478. class DAEMON_KERNELD: public DAEMON{
  479.     /*~PROTOBEG~ DAEMON_KERNELD */
  480.     /*~PROTOEND~ DAEMON_KERNELD */
  481. };
  482. class DAEMON_SSHD: public DAEMON{
  483.     /*~PROTOBEG~ DAEMON_SSHD */
  484. public:
  485.     int startif (void);
  486.     /*~PROTOEND~ DAEMON_SSHD */
  487. };
  488.  
  489. /*
  490.     Restart sshd if ETC_SSH_HOST_KEY is newer than the process
  491. */
  492. PUBLIC int DAEMON_SSHD::startif ()
  493. {
  494.     /* #Specification: sshd / strategy
  495.         sshd depends on /etc/ssh_host_key at least.
  496.         If the file is empty or do not exist, then sshd
  497.         is not need. It will be killed, or not started.
  498.  
  499.         If ssh_host_key is not empty, it will be started. If it is
  500.         already running and the file is younger than the process,
  501.         it will be kill and restart.
  502.  
  503.     */
  504.     return startif_file(f_ssh_host_key);
  505. }
  506.  
  507. /*
  508.     Create an instance of a sub-class of DAEMON based on its name.
  509. */
  510. DAEMON *daemon_new (
  511.     int managed,
  512.     const char *name,
  513.     const char *buf,
  514.     DAEMON *next)
  515. {
  516.     DAEMON *ret = NULL;
  517.     #define NEWD(n,c) if(strcmp(name,n)==0){ \
  518.         ret = new DAEMON_##c; \
  519.         }
  520.     NEWD("inetd",INETD)
  521.     else NEWD ("chat",COMMAND)
  522.     else NEWD ("crond",CROND)
  523.     else NEWD ("rpc.portmap",PORTMAP)
  524.     else NEWD ("named",NAMED)
  525.     else NEWD ("routed",ROUTED)
  526.     else NEWD ("ypbind",YPBIND)
  527.     else NEWD ("amd",AMD)
  528.     else NEWD ("klogd",KLOGD)
  529.     else NEWD ("syslogd",SYSLOGD)
  530.     else NEWD ("rpc.nfsd",NFSD)
  531.     else NEWD ("rpc.mountd",MOUNTD)
  532.     else NEWD ("lpd",LPD)
  533.     else NEWD ("ifconfig",COMMAND)
  534.     else NEWD ("ipx_configure",COMMAND)
  535.     else NEWD ("ipx_interface",COMMAND)
  536.     else NEWD ("kerneld",KERNELD)
  537.     else NEWD ("route",COMMAND)
  538.     else NEWD ("clock",COMMAND)
  539.     else NEWD ("rarp",COMMAND)
  540.     else NEWD ("lilo",COMMAND)
  541.     else NEWD ("netdate",COMMAND)
  542.     else NEWD ("makemap",COMMAND)
  543.     else NEWD ("modprobe",COMMAND)
  544.     else NEWD ("depmod",COMMAND)
  545.     else NEWD ("pppd",COMMAND)
  546.     else NEWD ("fdisk",COMMAND)
  547.     else NEWD ("telinit",COMMAND)
  548.     else NEWD ("mount",COMMAND)
  549.     else NEWD ("nslookup",COMMAND)
  550.     else NEWD ("umount",COMMAND)
  551.     else NEWD ("gated",GATED)
  552.     else NEWD ("sendmail",SENDMAIL)
  553.     else NEWD ("sshd",SSHD)
  554.     else{
  555.         xconf_error (MSG_U(E_UNKNOWNDAEMON
  556.             ,"Unknown daemon :%s:....\ndon't know how to support it\n")
  557.             ,name);
  558.     }
  559.     if (ret != NULL){
  560.         ret->init(managed,name,buf,next);
  561.     }
  562.     return ret;
  563. }
  564.  
  565.